package com.anntly.netty.heartbeat;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.IdleStateHandler;

import java.util.concurrent.TimeUnit;

/**
 * @Auther: 张文
 * @Date: 2020/6/7 10:23
 * @Description: 虽然Handler可以实现channelInactive接口处理客户端关闭，但是客户端异常关闭需要用心跳机制进行监听
 */
public class HeartbeatServer {

    private static final Integer port = 8888;

    public static void main(String[] args) throws InterruptedException {
        EventLoopGroup boosGroup = new NioEventLoopGroup(1);
        EventLoopGroup workGroup = new NioEventLoopGroup();
        ServerBootstrap bootstrap = new ServerBootstrap();
        try {
            bootstrap.group(boosGroup, workGroup)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG,128)
                    .childOption(ChannelOption.SO_KEEPALIVE,true)
                    .handler(new LoggingHandler(LogLevel.INFO)) // boosGroup的日志记录
            .childHandler(new ChannelInitializer<SocketChannel>() {
                @Override
                protected void initChannel(SocketChannel socketChannel) throws Exception {
                    ChannelPipeline pipeline = socketChannel.pipeline();
                    // 加入netty提供的IdleStateHandler 用于心跳监听
                    /*
                     * 1. IdleStateHandler 是netty提供的处理空闲状态的处理器
                     * 2. long readStateHandler : 表示多长时间没有读，就会发送一个心跳检查包
                     * 3. long writerIdleTime : 表示多长时间没有写，就会发送一个心跳检查包
                     * 4. long allIdleTime : 表示多长时间没有读写，就会发送一个心跳检测包
                     * 5. 当IdleStateEvent触发后，就会传递给管道的下一个handler去处理IdleStateEvent(userEventTriggered)
                     **/
                    pipeline.addLast(new IdleStateHandler(3,5,7, TimeUnit.SECONDS));
                    pipeline.addLast(new HeartbeatHandler());
                }
            });
            ChannelFuture channelFuture = bootstrap.bind(port).sync();
            channelFuture.channel().closeFuture().sync();

        }finally {
            boosGroup.shutdownGracefully();
            workGroup.shutdownGracefully();
        }
    }
}
